////////////////////////////////////////////////////////////////
//
//       Filename:  ExplorerSystem.go
//
//        Version:  1.0
//        Created:  2022年11月02日 11时44分51秒
//       Revision:  none
//       Compiler:  go
//
//         Author:  alpha
//   Organization:  alpha
//       Contacts:  chenxinquan@kylinos.com
//
////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////
// Description:
////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////
// Log:
////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////
// Todo:
//
////////////////////////////////////////////////////////////////

package genmai

import (
    "os"
    "fmt"
    "time"
    "syscall"
    sandbox "main/genmai/Sandbox"
    inter "main/genmai/Interpreter"
)

type
ExplorerConfigSystem struct {
    FormatVer           int
    Id                  string
    Belong              string
    PocHazardLevel      string
    Source              string
    SiteInfo            SiteInfo
    SiteRequests        SiteRequests
}

type
ExplorerSystem struct {
    ExplorerCommon
    /* */
    EsSandbox       sandbox.SandboxBase
}

var errMap = map[string]string{
    "0":"signal: segmentation fault (core dumped)",
    "1":"signal: aborted (core dumped)",
    "2":"exit status 1",
}


///////////////////////////////
// ExplorerSystem functions
func
(es *ExplorerSystem)GetExplorerConfigSystem() (config *ExplorerConfigSystem, rc error) {
    cf, ret := es.ExplorerCommon.EcConfig.(*ExplorerConfigSystem)
    /* */
    if (true == ret) {
        rc = nil
    } else {
        // TODO: ERR_CONVERSION_FAILED
    }

    config = cf
    /* */
    return config, rc
}

func
(es *ExplorerSystem)SetupSandbox(sb sandbox.SandboxBase) {
    es.EsSandbox    = sb
    /* */
    es.isSetup      = true
}

func
(es *ExplorerSystem)exploreWithPath(interpreter string,interArgs []string,exec string,
                                  args ...string  ) error {
    interio , rc := es.EsSandbox.Process(interpreter,interArgs,exec, args...)
    /* */
    if (nil != rc) {
        A_DEBUG_ERROR("exploreWithPath()->Process() error! rc = ", rc)
        
        /* */
        return rc
    }
    config, rc1 := es.GetExplorerConfigSystem()
    rc = rc1
    if (nil != rc) {
        A_DEBUG_ERROR("exploreWithPath()-> "+
                      "GetExplorerConfigSystem() error ! rc = ",
                      rc                                        )
        /* */
        return rc
    } // if (nil != ...

    ///////////////////////////////
    // Expire timer
    var expiretime int
    if (0 != config.SiteRequests.Implement.ExpireTime) {
        expiretime = config.SiteRequests.Implement.ExpireTime
    } else {
        expiretime = 5 // 默认为五秒
    } // if (0 != ...
    /* */
    f := func() {
        // 想杀死整个进程组，而不是单个进程，需要传递负整数形式
        syscall.Kill(-interio.Cmd.Process.Pid, syscall.SIGKILL)
        A_DEBUG_WARNING("ID:", config.Id,
                        "takes too long! (Expiredtime = ", expiretime, "seconds)")

    }
    /* */
    timer_ := time.AfterFunc(time.Duration(expiretime) * time.Second, f)
    /* */
    defer timer_.Stop()

    for _, itr := range config.SiteRequests.Implement.Inter {
        icmd        := itr[ : inter.INTERPRETER_CMD_LEN]
        icmd_len    := len(icmd)
        for a:=0; a < 100000; a++ {
            ;
        }
        switch (icmd) {
            case inter.INTERPRETER_CMD_SEND:
                interio.Send(itr[ icmd_len : ] + "\n")
                // TODO:remove it: just for debug
                A_DEBUG_INFO("iio:", inter.INTERPRETER_CMD_SEND, itr[ icmd_len : ])

            case inter.INTERPRETER_CMD_RECV:
                // TODO
                //out, rc_t := interio.Recv( icmd_len )
                interio.Recv( len(itr[ icmd_len :]) )
                // TODO:remove it: just for debug
                A_DEBUG_INFO("iio:", inter.INTERPRETER_CMD_RECV, itr[ icmd_len : ])

            case inter.INTERPRETER_CMD_RECVUNTIL:
                interio.RecvUntil( itr[ icmd_len : ] )
                // TODO:remove it: just for debug
                A_DEBUG_INFO("iio:", inter.INTERPRETER_CMD_RECVUNTIL, itr[ icmd_len : ])

            //case ">.":
            //    A_DEBUG_INFO(">.")
            //
            //case "<?":
            //    A_DEBUG_INFO("<?")
            //
            case inter.INTERPRETER_CMD_RECV_POC_CHECK:
                ou, _ := interio.Recv( len (itr[icmd_len : ]) )
                // TODO:remove it: just for debug
                A_DEBUG_INFO("iio:", inter.INTERPRETER_CMD_RECV_POC_CHECK, itr[ icmd_len : ])
                A_DEBUG_INFO("a ou:", ou)
                /* */
                if ( ou == itr[ icmd_len : ] ) {
                    // A_DEBUG_INFO("exploreWithPath():",
                    //              "\"" +
                    //               inter.INTERPRETER_CMD_RECV_POC_CHECK +
                    //               "\":"                                 ,
                    //               config.Id+" "+"Check poc successfully!"              )
                                  systemPass:="System info: "+config.Id+" "+"Check poc successfully!" 
                                  fmt.Printf("%c[%d;%d;%dm%s%c[0m\n", 0x1B, 0, 0, 32, systemPass, 0x1B)
                    /* */
                    return RC_POC_CHECK_SUCCESSFULLY
                } else {
                }
            case inter.INTERPRETER_CMD_RECV_POC_CHECK_RC:
                ou, _ := interio.Recv( len (itr[icmd_len : ]) )
                // TODO:remove it: just for debug
                A_DEBUG_INFO("iio:", inter.INTERPRETER_CMD_RECV_POC_CHECK_RC, itr[ icmd_len : ])
                A_DEBUG_INFO("a ou:", ou)

                rc_:= interio.Cmd.Wait()

                //if ( "0" == itr[ icmd_len : ] ) {
                    fmt.Println(1111111111111,rc_.Error())
                    if (rc_.Error() == errMap[itr[ icmd_len : ]]) {
                            // A_DEBUG_INFO("exploreWithPath():",
                            //              inter.INTERPRETER_CMD_RECV_POC_CHECK_RC,
                            //              config.Id+" "+"Check poc failed!"            )
                                        systemfail:="System info: "+config.Id+" "+"Check poc successfully!" 
                                        fmt.Printf("%c[%d;%d;%dm%s%c[0m\n", 0x1B, 0, 0, 32, systemfail, 0x1B)
                            /* */
                            return RC_POC_CHECK_SUCCESSFULLY
                    } else {
                    }
                //}
        } // switch (inter ...
    } // for _ , itr

                        // A_DEBUG_INFO("exploreWithPath():",
                    //              inter.INTERPRETER_CMD_RECV_POC_CHECK,
                    //              config.Id+" "+"Check poc failed!"            )
                    systemfail:="System info: "+config.Id+" "+"Check poc failed!" 
                    fmt.Printf("%c[%d;%d;%dm%s%c[0m\n", 0x1B, 0, 0, 34, systemfail, 0x1B)
       /* */
    return RC_POC_CHECK_FAILED

    // return rc
}


///////////////////////////////
// override ExplorerBase functions
func
(es *ExplorerSystem)Explore() (expvul VulnInfoCommon, rc error) {
    config, rc_t := es.GetExplorerConfigSystem()
    rc = rc_t
    if (nil != rc) {
        A_DEBUG_ERROR("Explore()->GetExplorerConfigSystem() "+
                      "error! rc = ", rc                    )
        /* */
        return VulnInfoCommon{}, rc
    }

    ///////////////
    // starting explore
    fmt.Println(config)
    for _, im := range config.SiteRequests.ImArray {
        rc = es.exploreWithPath(im.Inter,im.InterArgs,es.ExplorerCommon.EcConfigFilePrefix +
                               string(os.PathSeparator)+im.Exec,im.Args...                                  )
        /* */
        if rc.Error() =="Poc Check Successfully!"{
            expvul.VICId             = config.Id
            expvul.VICBelong         = config.Belong
            expvul.VICPocHazardLevel = config.PocHazardLevel
            expvul.VICSource         = config.Source
            expvul.VICSiteInfo       = config.SiteInfo
        }
        
    } // for _, im ...
    // ending explore
    ///////////////

    return expvul, nil
}

///////////////////////////////
// override functions
